<template>
	<view class="y-tab__pane" :data-index="index" :class="[uniquePaneClass,paneClass]" :style="[paneStyle]">
		<!-- 渲染过的则不再渲染，未渲染的根据激活状态进行渲染 -->
		<view class="y-tab__pane--wrap" v-if="rendered ? true : active">
			<slot />
		</view>
	</view>
</template>

<script>
	/**
	 * y-tab 标签
	 * @description 选项卡组件的子组件，搭配y-tabs使用
	 * @property {String | Number}	name		             标签名称，作为匹配的标识符。默认为标签的索引值
	 * @property {String}			title		             标题
	 * @property {Boolean}			disabled	             是否禁用标签，默认false
	 * @property {String}			dot	                     是否在标题右上角显示小红点（优先级高于badge）。默认false
	 * @property {String | Number}	badge	                 图标右上角徽标的内容
	 * @property {String | Number}	badge-max-count	         徽标数最大数字限制，超过这个数字将变成badgeMaxCount+，如果传空字符串则不设置。默认99
	 * @property {Object}       	title-style	             自定义标题样式
	 * @property {Boolean}			title-class	             自定义标题类名
	 * @property {String}	        icon-type	             图标图案，为uniapp扩展组件（uni-ui）下的uni-icons的type值，customPrefix用法等同
	 * @property {String | Number}	icon-size	             图标大小，默认16
	 * @property {String}			custom-prefix	         自定义图标
	 * @property {String}			image-src	             图片路径
	 * @property {String}			image-mode	             图片裁剪、缩放的模式，为uniapp内置组件->媒体组件—>image下的mode属性的可选值
	 * @property {String}			position	             在有图标或图片的情况下，标题围绕它们所在的位置，默认right。可选值：left、top、bottom
	 */

	import { isNull, toClass, getUid } from '../js/uitls';
	import { options } from '../js/const';

	export default {
		name: 'y-tab',
		options,
		props: {
			title: String, // 标题
			disabled: Boolean, // 是否禁用标签
			dot: Boolean, // 是否在标题右上角显示小红点
			badge: {
				type: [Number, String],
				default: ''
			}, // 图标右上角徽标的内容
			// 徽标数最大数字限制,超过这个数字将变成badgeMaxCount+,如果传空字符串则不设置
			badgeMaxCount: {
				type: [Number, String],
				default: 99
			},
			name: [Number, String], // 标签名称，作为匹配的标识符
			titleStyle: Object, //	自定义标题样式
			titleClass: String, //	自定义标题类名
			iconType: String, //图标图案，为uniapp扩展组件（uni-ui）下的uni-icons的type值，customPrefix用法等同
			iconSize: {
				type: [Number, String],
				default: 16
			}, //图标大小
			customPrefix: String, //自定义图标
			imageSrc: String, //图片路径
			imageMode: {
				type: String,
				default: 'scaleToFill',
				validator(value) {
					return [
						'scaleToFill',
						'aspectFit',
						'aspectFill',
						'widthFix',
						'heightFix',
						'top',
						'bottom',
						'center',
						'left',
						'right',
						'top left',
						'top right',
						'bottom left',
						'bottom right'
					].includes(value);
				}
			}, //图片裁剪、缩放的模式，为uniapp内置组件->媒体组件—>image下的mode值
			position: {
				type: String,
				default: 'right',
				validator(value) {
					return ['top', 'bottom', 'left', 'right'].includes(value);
				}
			} //如果存在图片或图标，标题围绕它们的位置
		},
		data() {
			return {
				isUnmounted: false,
				index: -1, //内容卡片对应的下标
				// parent: null, //父元素实例
				active: false, //是否为激活状态
				rendered: false, //是否渲染过
				swipeable: false, //是否开启手势滑动切换
				paneStyle: null, //内容样式
				scrollspy: false, //是否为滚动导航模式
				// paneObserver: null, //pane交叉观察器
				isDisjoint: false, //当前pane是否与参照节点布局区域相离
				isActiveLast: false // 最后一个pane在滚动导航模式下是否激活对应的标签项
			};
		},
		computed: {
			computedName() {
				return !isNull(this.name) ? this.name : this.index;
			},
			unqieKey() {
				return getUid();
			},
			// 保证唯一的样式
			uniquePaneClass() {
				return 'y-tab__pane' + this.unqieKey
			},
			// 内容class
			paneClass() {
				return toClass({ 'is-active': this.active, 'is-scrollspy': this.scrollspy });
			},
		},
		watch: {
			$props: {
				deep: true,
				// immediate: true,
				handler(newValue, oldValue) {
					// 更新tab
					if (this.parent) {
						this.parent.updateTab({
							newValue: { ...newValue, badge: this.formatBadge() },
							oldValue: oldValue && { ...oldValue },
							index: this.index
						});
					}
				}
			}
		},
		created() {
			this.parent = this.getParent();
		},
		mounted() {
			if (!this.parent) return;
			if (this.parent.childrens.indexOf(this) === -1) this.parent.childrens.push(this);
			this.parent.putTab({ newValue: { ...this.$props, key: this.unqieKey, badge: this.formatBadge() } });
			this.scrollspy = this.parent.scrollspy; // 是否为滚动导航
			this.rendered = !this.parent.isLazyRender || this.scrollspy; //标记是否渲染过，非懒加载与滚动导航模式下默认渲染
		},
		// #ifndef VUE3
		destroyed() {
			if (this.isUnmounted) return;
			this.unInit();
		},
		// #endif
		// #ifdef VUE3
		unmounted() {
			this.isUnmounted = true;
			this.unInit();
		},
		// #endif
		methods: {
			// 徽标格式化
			formatBadge() {
				if (!isNull(this.badge) && !isNull(this.badgeMaxCount) && this.badge > this.badgeMaxCount) {
					return this.badgeMaxCount + '+';
				} else {
					return this.badge
				}
			},
			// 获取查询节点信息的对象
			getSelectorQuery() {
				let query = null;
				// #ifdef MP-ALIPAY
				query = uni.createSelectorQuery();
				// #endif
				// #ifndef MP-ALIPAY
				query = uni.createSelectorQuery().in(this);
				// #endif
				return query;
			},
			// 获取元素位置信息
			getRect(selector) {
				return new Promise((resolve, reject) => {
					selector = `.${this.uniquePaneClass}` + (!isNull(selector) ? " " + selector : '')
					this.getSelectorQuery()
						.select(selector)
						.boundingClientRect()
						.exec(rect => {
							resolve(rect[0] || {});
						});
				});
			},
			// 卸载组件的处理
			unInit() {
				this.disconnectObserver(); //销毁观察器
				if (this.parent) {
					const index = this.parent.childrens.findIndex(item => item === this);
					this.parent.childrens.splice(index, 1);
					this.parent.tabs.splice(index, 1);
					this.parent.tabRects.splice(index, 1);
				}
			},
			//获取父元素实例
			getParent(name = 'y-tabs') {
				let parent = this.$parent;
				let parentName = parent.$options.name;
				while (parentName !== name) {
					parent = parent.$parent;
					if (!parent) return false;
					parentName = parent.$options.name;
				}

				return parent;
			},
			// 断掉观察，释放资源
			disconnectObserver() {
				this.paneObserver && this.paneObserver?.disconnect();
			},
			// 观察 - 标签内容滚动时定位标签项
			async observePane(top) {
				this.disconnectObserver();
				const paneObserver = uni.createIntersectionObserver(this, { thresholds: [0, 0.01, 0.99, 1] });


				// 注意：如果y-tabs使用的区域滚动，整个页面的布局跟随页面滚动，当pane跟随页面移动了之后，
				//      那么y-tabs__content的top就会变化，导致交互区域位置不准确，可以在onPageScroll使用定时器实现滚动结束的处理重新resize一下组件创建pane的监听
				// 如果pane内容超过页面的可视区域，最好舍弃这种交互布局，uniapp未实现Android的嵌套滑动机制，页面滑动到底后无法将事件分发给scroll-view，使scroll-view继承滑动

				paneObserver.relativeToViewport({ top: -top }); // 到屏幕顶部的高度时触发
				// 不能观察根节点 unk-vendors.js:14596 [system] Node .y-tab__pane9 is not found. Intersection observer will not trigger.
				paneObserver.observe(`.${this.uniquePaneClass} .y-tab__pane--wrap`, res => {
					// console.log('res:', this.title, res);
					if (!this.isActiveLast) {
						// 如果目标节点布局区域的top小于参照节点的top,则说明目标节点在参照节点布局区域之上，intersectionRatio不大于0则说明两者不相交
						this.isDisjoint = res.intersectionRatio <= 0 && res.boundingClientRect.top < res
							.relativeRect.top;
					} else {
						// 滚动导航模式下，最后一个pane完成显示但未超出可视范围顶部时，是否设置相离而激活最后一个标签项
						this.isDisjoint = res.intersectionRatio > 0 && res.boundingClientRect.bottom <= res
							.relativeRect.bottom;
					}

					// 保证组件初始化完成时执行，避免创建时触发一次监听器的回调函数，导致执行顺序先于tabs的init方法，使底部条错位:
					// 标签栏点击时触发的滚动不允许设置激活下标
					if (this.parent.isLoaded && !this.parent.lockedScrollspy) this.parent
						.setActivedIndexToScroll();
				});
				this.paneObserver = paneObserver;
			},
		}
	};
</script>

<style lang="scss" scoped>
	@import '../css/index.scss';
</style>